package com.modifiertech.lineage.client;

import com.modifiertech.lineage.Lineage;
import com.modifiertech.lineage.api.PlayerData;
import com.modifiertech.lineage.api.PlayerDataSkill;
import com.modifiertech.lineage.base.CommonProxy;
import com.modifiertech.lineage.client.gui.LevelAndExpRender;
import com.modifiertech.lineage.client.gui.ftbint.GuiLineageV2;
import com.modifiertech.lineage.commands.SPCmdHelper;
import com.modifiertech.lineage.effect.EffectApplier;
import com.modifiertech.lineage.event.ClientEventHandler;
import com.modifiertech.lineage.event.PlayerDataHandler;
import com.modifiertech.lineage.handler.ClientSelectedRangeHandler;
import com.modifiertech.lineage.network.*;
import com.modifiertech.lineage.skills.RangeHealth;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;

import java.util.*;
import java.util.function.Supplier;

public class ClientProxy extends CommonProxy {
    Logger logger = LogManager.getLogger(ClientProxy.class);

    public static FakePlayer fakePlayer;

    public static final KeyBinding levelsguiKeyBind =
            new KeyBinding("技能升级界面",
                    Keyboard.KEY_L, "血脉Lineage");
//    public static final KeyBinding rightMouse=
//            new KeyBinding("技能增强键",
//                    Mouse.,"血脉Lineage");

    public static final KeyBinding skill1 =
            new KeyBinding("技能快捷键0",
                    Keyboard.KEY_F, "血脉Lineage");
    public static final KeyBinding skill2 =
            new KeyBinding("技能快捷键1",
                    Keyboard.KEY_NUMPAD8, "血脉Lineage");
    public static final KeyBinding skill3 =
            new KeyBinding("技能快捷键3",
                    Keyboard.KEY_NUMPAD9, "血脉Lineage");
    public static final KeyBinding skill4 =
            new KeyBinding("技能快捷键4",
                    Keyboard.KEY_NUMPAD4, "血脉Lineage");
    public static final KeyBinding skill5 =
            new KeyBinding("技能快捷键5",
                    Keyboard.KEY_NUMPAD5, "血脉Lineage");
    public static final KeyBinding skill6 =
            new KeyBinding("技能快捷键6",
                    Keyboard.KEY_NUMPAD6, "血脉Lineage");
    public static final KeyBinding skill7 =
            new KeyBinding("技能快捷键7",
                    Keyboard.KEY_NUMPAD2, "血脉Lineage");
    public static final KeyBinding skill8 =
            new KeyBinding("技能快捷键8",
                    Keyboard.KEY_NUMPAD3, "血脉Lineage");

    @Override
    public void preInit(FMLPreInitializationEvent event) {
        super.preInit(event);
        MinecraftForge.EVENT_BUS.register(LevelAndExpRender.INSTANCE);
        MinecraftForge.EVENT_BUS.register(ClientEventHandler.INSTANCE);
    }

    @Override
    public void init(FMLInitializationEvent event) {
        MinecraftForge.EVENT_BUS.register(this);
        ClientRegistry.registerKeyBinding(levelsguiKeyBind);
        ClientRegistry.registerKeyBinding(skill1);
        ClientRegistry.registerKeyBinding(skill2);
        ClientRegistry.registerKeyBinding(skill3);
        ClientRegistry.registerKeyBinding(skill4);
        ClientRegistry.registerKeyBinding(skill5);
        ClientRegistry.registerKeyBinding(skill6);
        ClientRegistry.registerKeyBinding(skill7);
        super.init(event);
    }

    @Override
    public EntityPlayer getClientPlayer() {
        return Minecraft.getMinecraft().player;
    }

    @Override
    public String getLocalizedString(String string) {
        return I18n.format(string);
    }

    //监听键盘输入事件
    @SubscribeEvent
    @SideOnly(value = Side.CLIENT)
    public void keyListener(InputEvent.KeyInputEvent event) {
        boolean rightHold =
                Minecraft.getMinecraft().gameSettings.keyBindUseItem.isKeyDown();

        try {
            if (levelsguiKeyBind.isPressed()) {
                Minecraft mc = Minecraft.getMinecraft();
                if (mc.world.isRemote) {
//                mc.displayGuiScreen(new SkillTreeGUI());
//                    new TestGUIWithFtb2().openGui();
                    new GuiLineageV2().openGui();
                }
            } else if (skill1.isPressed()) {
                skillShortCutExecute(0, rightHold);
            } else if (skill2.isPressed()) {
                skillShortCutExecute(1, rightHold);
            } else if (skill3.isPressed()) {
                skillShortCutExecute(2, rightHold);
            } else if (skill4.isPressed()) {
                skillShortCutExecute(3, rightHold);
            } else if (skill5.isPressed()) {
                skillShortCutExecute(4, rightHold);
            } else if (skill6.isPressed()) {
                skillShortCutExecute(5, rightHold);
            } else if (skill7.isPressed()) {
                skillShortCutExecute(6, rightHold);
            } else if (skill8.isPressed()) {
                skillShortCutExecute(7, rightHold);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void renderLaser6(float partialTicks, PlayerData playerData) {
        Minecraft mc = Minecraft.getMinecraft();
        // 获取玩家的世界坐标
        Vec3d playerPos = new Vec3d(
                mc.player.prevPosX + (mc.player.posX - mc.player.prevPosX) * partialTicks,
                mc.player.prevPosY + (mc.player.posY - mc.player.prevPosY) * partialTicks,
                mc.player.prevPosZ + (mc.player.posZ - mc.player.prevPosZ) * partialTicks
        );

        // 获取鼠标指向的目标点
        RayTraceResult rayTraceResult = getMouseOver(partialTicks);

        if (rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK) {
            BlockPos blockPos = rayTraceResult.getBlockPos();
            highlightSurroundingBlocks(blockPos, playerData);  // 高亮方块
            //标记为合法
            playerData.updateSkillRangeAvailableStatus(true);
        } else {
            //标记为不在有效范围
            playerData.updateSkillRangeAvailableStatus(false);
            //AABB盒清空
            playerData.updateSkillRangeAABBList(new ArrayList<AxisAlignedBB>());
        }
    }

    /**
     * 高亮附近方块
     *
     * @param centerPos
     */
    private static void highlightSurroundingBlocks(BlockPos centerPos, PlayerData playerData) {
        // 遍历以目标方块为中心的3x3区域
        Set<Entity> highlightEntityIdList = new HashSet<>();
        List<AxisAlignedBB> aaAlignedBBs = new ArrayList<AxisAlignedBB>();
        BlockPos tempMin = null;
        BlockPos tempMax = null;

        for (int dx = -1; dx <= 1; dx++) {
            for (int dz = -1; dz <= 1; dz++) {
                //
                BlockPos targetPos = centerPos.add(dx, 0, dz);
                if (null == tempMin) {
                    tempMin = targetPos.add(-0.5, 0, -0.5);
                }
                tempMax = targetPos.add(1.5, 3, 1.5);

                //AABB盒
                AxisAlignedBB temp = new AxisAlignedBB(
                        targetPos.add(-0.5, 0, -0.5), targetPos.add(1.5, 3, 1.5));
                highlightEntityIdList.addAll(highlightBlockUpEntity(targetPos, temp));
            }
        }
        aaAlignedBBs.add(new AxisAlignedBB(tempMin, tempMax));
        //更新选中的AABB盒范围,用来执行服务器选中实体
        playerData.updateSkillRangeAABBList(aaAlignedBBs);
        //客户端保持AABB盒中始终高亮
        ClientSelectedRangeHandler.INSTANCE.update(highlightEntityIdList);
    }

    /**
     * 高亮某一方块
     *
     * @param blockPos
     */
    private static void highlightBlock(BlockPos blockPos) {
        Minecraft mc = Minecraft.getMinecraft();

        // 获取当前相机的位置
        Vec3d cameraPos = new Vec3d(
                mc.getRenderViewEntity().prevPosX + (mc.getRenderViewEntity().posX - mc.getRenderViewEntity().prevPosX) * mc.getRenderPartialTicks(),
                mc.getRenderViewEntity().prevPosY + (mc.getRenderViewEntity().posY - mc.getRenderViewEntity().prevPosY) * mc.getRenderPartialTicks(),
                mc.getRenderViewEntity().prevPosZ + (mc.getRenderViewEntity().posZ - mc.getRenderViewEntity().prevPosZ) * mc.getRenderPartialTicks()
        );

        // 偏移量，使得绘制的边框在方块的边缘
        double x = blockPos.getX() - cameraPos.x;
        double y = blockPos.getY() - cameraPos.y;
        double z = blockPos.getZ() - cameraPos.z;

        // 开始绘制边框
        GlStateManager.pushMatrix();
        GlStateManager.pushAttrib();
        GlStateManager.disableTexture2D();
        GlStateManager.disableLighting();
        GlStateManager.disableDepth();
        GlStateManager.enableBlend();
        GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GlStateManager.color(1.0F, 1.0F, 0.0F, 0.5F);  // 黄色，50%透明度

        // 设置线宽
        GlStateManager.glLineWidth(2.0F);

        // 绘制边框
        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder buffer = tessellator.getBuffer();
        buffer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION);

        // 绘制方块最上面的4条边
        buffer.pos(x, y + 1, z).endVertex();       // 顶点1 (x, y + 1, z)
        buffer.pos(x + 1, y + 1, z).endVertex();   // 顶点2 (x + 1, y + 1, z)

        buffer.pos(x + 1, y + 1, z).endVertex();   // 顶点2 (x + 1, y + 1, z)
        buffer.pos(x + 1, y + 1, z + 1).endVertex();// 顶点3 (x + 1, y + 1, z + 1)

        buffer.pos(x + 1, y + 1, z + 1).endVertex();// 顶点3 (x + 1, y + 1, z + 1)
        buffer.pos(x, y + 1, z + 1).endVertex();   // 顶点4 (x, y + 1, z + 1)

        buffer.pos(x, y + 1, z + 1).endVertex();   // 顶点4 (x, y + 1, z + 1)
        buffer.pos(x, y + 1, z).endVertex();       // 顶点1 (x, y + 1, z)
        tessellator.draw();

        // 恢复 OpenGL 状态
        GlStateManager.enableDepth();
        GlStateManager.enableLighting();
        GlStateManager.enableTexture2D();
        GlStateManager.disableBlend();
        GlStateManager.popAttrib();
        GlStateManager.popMatrix();
        // 这里可以添加代码来高亮指定的方块
        // 例如，通过绘制边框或改变方块颜色
    }


    /**
     * 高亮某一方块以及方块上的实体
     *
     * @param blockPos
     * @return 返当前高亮列表实体id 集合
     */
    private static Set<Entity> highlightBlockUpEntity(BlockPos blockPos, AxisAlignedBB alignedBB) {
        highlightBlock(blockPos);
        Minecraft mc = Minecraft.getMinecraft();
        // 这里可以添加代码来高亮指定的方块
        // 获取方块位置上方3格范围内的实体列表
        List<Entity> entities = mc.world.getEntitiesWithinAABB(Entity.class, alignedBB);
        // 高亮客户端实体 id 信息列表
        Set<Entity> entitiesTemp = new HashSet();
        // 对每个实体应用发光效果
        for (Entity entity : entities) {
            if (entity instanceof EntityLivingBase) {
                EffectApplier.applyGlowingClientOnly((EntityLivingBase) entity);
                //维护实体唯一id
                //当前版本world 获取 entity 仅提供使用int 方法
                entitiesTemp.add(entity);
            }
        }
        return entitiesTemp;
    }

    // 这里可以添加代码来高亮指定的实体
    // 例如，通过启用实体发光或绘制边框
    public static RayTraceResult getMouseOver(float partialTicks) {
        Minecraft mc = Minecraft.getMinecraft();
        if (mc.getRenderViewEntity() != null) {
            return mc.getRenderViewEntity().rayTrace(10, partialTicks);  // 最大检测距离为5格
        }
        return null;
    }


    /**
     * 根据快捷键技能index 执行快捷键对应技能
     *
     * @param index
     */
    public void skillShortCutExecute(int index, boolean enhance) {
        PlayerData playerData = PlayerDataHandler.get(Minecraft.getMinecraft().player);
        Optional<PlayerDataSkill> playerDataSkill = playerData.getPlayerDataSkillBySkillShortCutIndex(index);
        if (playerDataSkill.isPresent()) {
            MessageAnimateCall messageAnimateCall = new MessageAnimateCall();
            messageAnimateCall.write(playerDataSkill.get().getSkillName(), enhance);
            //通讯
            NetworkHandler.INSTANCE.sendToServer(messageAnimateCall);
        } else {
            SPCmdHelper.execClientSay(new TextComponentString("快捷键 " + index + " 无有效技能绑定！"));
        }
    }

    public void registerFakePlayer() {
        if (null == fakePlayer) {
            try {
                WorldServer worldServer = DimensionManager.getWorld(0); // default world
                GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "FakePlayer");
                fakePlayer = new FakePlayer(worldServer, gameProfile);
            } catch (Exception e) {
                logger.error(e);
            }
        }
    }

    @Override
    public void handleMessageClientSay(MessageClientSay messageClientSay, MessageContext messageContext) {
        String message = messageClientSay.getNbtTagCompound().getString("word");
        Minecraft.getMinecraft().player.sendMessage(new TextComponentString(message));
    }

    @Override
    public void handleMessageClientSkillJumpSplash(MessageClientSkillJumpSplash message, MessageContext messageContext) {
        // 获取玩家的位置
        BlockPos playerPos = new BlockPos(message.getNbtTagCompound().getDouble("x"),
                message.getNbtTagCompound().getDouble("y"), message.getNbtTagCompound().getDouble("z"));
        World world = Minecraft.getMinecraft().world;
        // 粒子效果的半径
        double radius = 2.0;
        // 粒子的数量
        int particleCount = 36; // 一个完整的圆环
        double[] radii = {radius, radius + 0.5}; // 两个不同的半径
        for (double r : radii) {
            for (int i = 0; i < particleCount; i++) {
                // 计算圆周上的点
                double angle = 2 * Math.PI * i / particleCount;
                double xOffset = r * Math.cos(angle);
                double zOffset = r * Math.sin(angle);
                // 生成粒子效果
                world.spawnParticle(
                        EnumParticleTypes.REDSTONE,
                        playerPos.getX() + xOffset,            // X 坐标
                        playerPos.getY(),                      // Y 坐标
                        playerPos.getZ() + zOffset,            // Z 坐标
                        0.0d, 0.5d, 0.0d// 粒子速度（X, Y, Z）
                );
            }
        }
    }

    @Override
    public void handleMessageClientSkillCD(MessageClientSkillCD messageClientSkillCD, MessageContext messageContext) {
        EntityPlayer entityPlayer = Minecraft.getMinecraft().player;
        PlayerData playerData = PlayerDataHandler.get(entityPlayer);
        playerData.setSkillCd(messageClientSkillCD.getNbtTagCompound().getString("skillName")
                , messageClientSkillCD.getNbtTagCompound().getLong("cdavailable"));
    }

    @Override
    public void handleMessageClientSkillHandingState(MessageClientSkillHandingState messageClientSkillHandingState, MessageContext messageContext) {
        EntityPlayer entityPlayer = Minecraft.getMinecraft().player;
        PlayerData playerData = PlayerDataHandler.get(entityPlayer);
        playerData.updateSkillHanding(messageClientSkillHandingState.getNbtTagCompound().getString("skillName")
                , messageClientSkillHandingState.getNbtTagCompound().getBoolean("state"));
    }

    @Override
    public void handleMessageClientSkillRange(MessageClientSkillRange messageClientSkillRange, MessageContext messageContext) {
        EntityPlayer entityPlayer = Minecraft.getMinecraft().player;
        PlayerData playerData = PlayerDataHandler.get(entityPlayer);
        if (messageClientSkillRange.getNbtTagCompound().hasKey("state")) {
            playerData.updateSkillRangeAvailableStatus(messageClientSkillRange
                    .getNbtTagCompound().getBoolean("state"));
        }
        if (messageClientSkillRange.getNbtTagCompound().hasKey("AlignedBBs")) {
            List<AxisAlignedBB> axisAlignedBBS = MessageClientSkillRange.readAABBRange(messageClientSkillRange
                    .getNbtTagCompound());
            playerData.updateSkillRangeAABBList(axisAlignedBBS);
        }
    }

    @Override
    public void handleMessageServerSkillRange(MessageServerSkillRange messageServerSkillRange, MessageContext messageContext, Supplier callback) {
        if (Lineage.isSinglePlayer()&& messageContext.side==Side.SERVER){
            super.handleMessageServerSkillRange(messageServerSkillRange,messageContext,callback);
        }
    }

    @Override
    public void handleRenderWorldLastEventRangeHealth(float partialTicks) {
        EntityPlayer entityPlayer = Minecraft.getMinecraft().player;
        PlayerData playerData = PlayerDataHandler.get(entityPlayer);
        if (playerData.checkSkillHanding(RangeHealth.skillName)) {
            renderLaser6(partialTicks, playerData);
        }
    }

    @Override
    public void handleOnPlayerSkillHandingOffRangeHealth(EntityPlayer entityPlayer, float health, Random random) {
        if (Lineage.isSinglePlayer()&& entityPlayer instanceof EntityPlayerMP){
            super.handleOnPlayerSkillHandingOffRangeHealth(entityPlayer,health,random);
        }
    }

    @Override
    public void handleOnPlayerTickRangeHealth(TickEvent.PlayerTickEvent event) {
        if (Lineage.isSinglePlayer()&& event.player instanceof EntityPlayerMP){
            super.handleOnPlayerTickRangeHealth(event);
        }
    }

    @Override
    public void handleOnTickPlayerManaHanding(TickEvent.PlayerTickEvent event) {
        if (Lineage.isSinglePlayer()&& event.player instanceof EntityPlayerMP){
            super.handleOnTickPlayerManaHanding(event);
        }
    }

    @Override
    public void handleOnTickPlayerSelectedRangeClear(TickEvent.PlayerTickEvent event) {
        ClientSelectedRangeHandler.INSTANCE.overTimeCheck();
    }

    @Override
    public void handleOnSkillRangeSelectedRender(float partialTicks) {
        PlayerData data = PlayerDataHandler.get(Minecraft.getMinecraft().player);
        if (data != null) {
            data.skillRangeSelectedRender(partialTicks);
        }
    }

    @Override
    public void handleOnPlayerSkillHandingOffAimBlock(PlayerInteractEvent.RightClickBlock event) {
        //按客户端处理,发送服务端消息 onPlayerSkillHandingOff 应订阅对应消息触发的服务端事件.
        handleOnPlayerSkillHandingOffAim(event.getEntityPlayer());
    }

    @Override
    public void handleOnPlayerSkillHandingOffAimEmpty(PlayerInteractEvent.RightClickEmpty event) {
        //按客户端处理,发送服务端消息 onPlayerSkillHandingOff 应订阅对应消息触发的服务端事件.
        handleOnPlayerSkillHandingOffAim(event.getEntityPlayer());
    }

    public void handleOnPlayerSkillHandingOffAim(EntityPlayer entityPlayer) {
        PlayerData data = PlayerDataHandler.get(entityPlayer);
        String skillName = data.getHoldingSkillName();
        if (data != null && null != skillName) {
            //客户端状态.
            boolean status = data.getSkillRangeAvailableStatus();
            List<AxisAlignedBB> axisAlignedBBS = data.getCachedAabbSkillRangeList();
            NetworkHandler.INSTANCE.sendToServer(new MessageServerSkillRange().write(status, axisAlignedBBS, skillName));
        }
    }

    //接收服务端推送的完整用户数据
    @Override
    public void handleOnMessageDataSync(MessageDataSync message){
        EntityPlayer entityPlayer = Minecraft.getMinecraft().player;
        PlayerData playerData = PlayerDataHandler.get(entityPlayer);
        playerData.loadFromNBT(message.nbtTagCompound);
    }

}
